package birdsong.comm;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.LinkedList;

import birdsong.comm.ServerSideMessage.Type;

/**
 * Communication manager for {@link birdsong.client.BirdsongClient Birdsong
 * clients}. Birdsong clients have this object to manage all the messages sent
 * by the server.
 * 
 * @author While True
 * @version 1
 */
public class DealWithServer {

	private Socket socket;
	private String clientNickname;
	private ClientCommunicator clientCommunicator;

	private ObjectInputStream in;
	private ObjectOutputStream out;

	private LinkedList<Thread> activeThreads = new LinkedList<Thread>();

	/**
	 * Constructor that receives a socket and a ClientComunicator. Will generate
	 * threads to take care of {@link OutputStream} and {@link InputStream}.
	 * Will add all threads generated to listThreadsActive for interruption
	 * purposes.
	 * 
	 * @param socket
	 *            Socket for the network interface.
	 * @param clientCommunicator
	 *            ClientCommunicator responsible for the communication of the
	 *            client.
	 * @throws IOException
	 *             Send an exception if the socket is closed.
	 */
	public DealWithServer(Socket socket, String clientNickname,
			ClientCommunicator clientCommunicator) throws IOException {
		this.socket = socket;
		this.clientNickname = clientNickname;
		this.clientCommunicator = clientCommunicator;
		in = new ObjectInputStream(socket.getInputStream());
		out = new ObjectOutputStream(socket.getOutputStream());

		getActiveThreads().add(new ThreadReceiverServer());
		getActiveThreads().add(new ThreadSenderServer());
		clientCommunicator.getClientSenderMessageList().add(new ServerMessage(Type.CLIENT_CONNECTED, null,	getClientNickname()));
 
	}

	/**
	 * Starts the 2 Threads:
	 * <ul>
	 * ThreadReceiverServer - manage the incoming server messages.
	 * </ul>
	 * <ul>
	 * ThreadSenderServer - manage the outcoming messages to the server.
	 * </ul>
	 */
	public void start() {
		for (Thread listThreads : getActiveThreads())
			listThreads.start(); 
	}
 
	/**
	 * Getter that returns the InputStreamer.
	 * 
	 * @return Returns the ObjectInputStream.
	 */
	public ObjectInputStream getIn() {
		return in;
	}

	/**
	 * Getter that returns the OutputStreamer.
	 * 
	 * @return Returns the ObjectInputStream.
	 */
	public ObjectOutputStream getOut() {
		return out;
	}

	/**
	 * Getter that returns the client nickname.
	 * 
	 * @return Returns the clientNickname.
	 */
	public String getClientNickname() {
		return clientNickname;
	}

	public LinkedList<Thread> getActiveThreads() {
		return activeThreads;
	}

	private class ThreadReceiverServer extends Thread {
		@Override
		public void run() { 
			try {
				while (!isInterrupted()) {
					ClientMessage message = (ClientMessage) getIn().readObject();
					clientCommunicator.getClientReceiverMessageList().add(message); 
				}
			} catch (Exception e) {}
		}
	} 

	private class ThreadSenderServer extends Thread {
		@Override
		public void run() {
			try {
				while (!isInterrupted()) {
					ServerMessage message = clientCommunicator.getClientSenderMessageList().take();
					getOut().writeObject(message);  
					if (message.getType().equals(Type.CLIENT_DISCONNECTED)) {
						try {
							socket.close();
							this.interrupt();
						} catch (IOException e) {
							e.printStackTrace(); 
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			} 

		}

	}
}